#include <fitz.h>
#include <mupdf.h>

pdf_pattern *
pdf_keeppattern(pdf_pattern *pat)
{
    assert(pat->refs > 0);
    pat->refs ++;
    return pat;
}

void
pdf_droppattern(pdf_pattern *pat)
{
    assert(pat->refs > 0);
    if (--pat->refs == 0)
    {
        if (pat->tree)
            fz_droptree(pat->tree);
        fz_free(pat);
    }
}

fz_error *
pdf_loadpattern(pdf_pattern **patp, pdf_xref *xref, fz_obj *dict, fz_obj *stmref)
{
    fz_error *error;
    pdf_pattern *pat;
    fz_stream *stm;
    fz_obj *resources;
    fz_obj *obj;
    pdf_csi *csi;

    *patp = pdf_finditem(xref->store, PDF_KPATTERN, stmref);
    if (*patp)
    {
        pdf_keeppattern(*patp);
        return nil;
    }

    pdf_logrsrc("load pattern %d %d {\n", fz_tonum(stmref), fz_togen(stmref));

    pat = fz_malloc(sizeof(pdf_pattern));
    if (!pat)
        return fz_outofmem;

    pat->refs = 1;
    pat->tree = nil;
    pat->ismask = fz_toint(fz_dictgets(dict, "PaintType")) == 2;
    pat->xstep = fz_toreal(fz_dictgets(dict, "XStep"));
    pat->ystep = fz_toreal(fz_dictgets(dict, "YStep"));

    /* Put item into store at once to prevent a recursive loop if its
    resources include itself */
    error = pdf_storeitem(xref->store, PDF_KPATTERN, stmref, pat);
    if (error)
        goto cleanup;

    pdf_logrsrc("mask %d\n", pat->ismask);
    pdf_logrsrc("xstep %g\n", pat->xstep);
    pdf_logrsrc("ystep %g\n", pat->ystep);

    obj = fz_dictgets(dict, "BBox");
    pat->bbox = pdf_torect(obj);

    pdf_logrsrc("bbox [%g %g %g %g]\n",
        pat->bbox.x0, pat->bbox.y0,
        pat->bbox.x1, pat->bbox.y1);

    obj = fz_dictgets(dict, "Matrix");
    if (obj)
        pat->matrix = pdf_tomatrix(obj);
    else
        pat->matrix = fz_identity();

    pdf_logrsrc("matrix [%g %g %g %g %g %g]\n",
        pat->matrix.a, pat->matrix.b,
        pat->matrix.c, pat->matrix.d,
        pat->matrix.e, pat->matrix.f);

    /*
     * Resources
     */

    obj = fz_dictgets(dict, "Resources");
    if (!obj) {
        error = fz_throw("syntaxerror: Pattern missing Resources");
        goto cleanup;
    }

    error = pdf_resolve(&obj, xref);
    if (error)
        goto cleanup;

    error = pdf_loadresources(&resources, xref, obj);

    fz_dropobj(obj);

    if (error)
        goto cleanup;

    /*
     * Content stream
     */

    pdf_logrsrc("content stream\n");

    error = pdf_newcsi(&csi, pat->ismask);
    if (error)
        goto cleanup;

    error = pdf_openstream(&stm, xref, fz_tonum(stmref), fz_togen(stmref));
    if (error)
        goto cleanup2;

    error = pdf_runcsi(csi, xref, resources, stm);

    fz_dropstream(stm);

    if (error)
        goto cleanup2;

    pat->tree = csi->tree;
    csi->tree = nil;

    pdf_dropcsi(csi);

    fz_dropobj(resources);

    pdf_logrsrc("optimize tree\n");
    fz_optimizetree(pat->tree);

    pdf_logrsrc("}\n");

    *patp = pat;
    return nil;

cleanup2:
    pdf_dropcsi(csi);
cleanup:
    pdf_droppattern(pat);
    return error;
}

